package com.ruoyi.paipan.common;

import com.ruoyi.paipan.utils.LunarUtil;
import com.ruoyi.paipan.utils.SolarUtil;

import java.util.*;

public class Lunar {
    public static List<String> JIE_QI = Arrays.asList("冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪");
    public static List<String> JIE_QI_IN_USE = Arrays.asList("DA_XUE", "冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "DONG_ZHI", "XIAO_HAN", "DA_HAN", "LI_CHUN", "YU_SHUI", "JING_ZHE");
    private int year;
    private int month;
    private int day;
    private int hour;
    private int minute;
    private int second;
    private Solar solar;
    private int timeGanIndex;
    private int timeZhiIndex;
    private int dayGanIndex;
    private int dayGanIndexExact;
    private int dayGanIndexExact2;
    private int dayZhiIndex;
    private int dayZhiIndexExact;
    private int dayZhiIndexExact2;
    private int monthGanIndex;
    private int monthZhiIndex;
    private int monthGanIndexExact;
    private int monthZhiIndexExact;
    private int yearGanIndex;
    private int yearZhiIndex;
    private int yearGanIndexByLiChun;
    private int yearZhiIndexByLiChun;
    private int yearGanIndexExact;
    private int yearZhiIndexExact;
    private int weekIndex;
    private LinkedHashMap<String,Solar> jieQi = new LinkedHashMap<>();
    private EightChar eightChar = null;

    public Lunar(int year, int month, int day, int hour, int minute, int second, Solar solar, LunarYear y) {
        this.year = year;
        this.month = month;
        this.day = day;
        this.hour = hour;
        this.minute = minute;
        this.second = second;
        this.solar = solar;
        compute(y);
    }

    public static Lunar fromYmd(int lunarYear, int lunarMonth, int lunarDay)
    {
        return fromYmdHms(lunarYear, lunarMonth, lunarDay, 0, 0, 0);
    }

    public static Lunar fromYmdHms(int lunarYear, int lunarMonth, int lunarDay, int hour, int minute, int second)
    {
        LunarYear y = LunarYear.fromYear(lunarYear);
        LunarMonth m = y.getMonth(lunarMonth);
        Solar noon = Solar.fromJulianDay(m.getFirstJulianDay() + lunarDay - 1);
        Solar solar = Solar.fromYmdHms(noon.getYear(), noon.getMonth(), noon.getDay(), hour, minute, second);
        if (noon.getYear() != lunarYear) {
            y = LunarYear.fromYear(noon.getYear());
        }
        return new Lunar(lunarYear, lunarMonth, lunarDay, hour, minute, second, solar, y);
    }

    public static Lunar fromDate(Date date)
    {
        return fromSolar(Solar.fromDate(date));
    }

    public static Lunar fromSolar(Solar solar)
    {
        LunarYear ly = LunarYear.fromYear(solar.getYear());
        int lunarYear = 0;
        int lunarMonth = 0;
        int lunarDay = 0;
        for (int i = 0; i < ly.getMonths().size(); i++) {
            LunarMonth m = ly.getMonths().get(i);
            int days = solar.subtract(Solar.fromJulianDay(m.getFirstJulianDay()));
            if(days < m.getDayCount()){
                lunarYear = m.getYear();
                lunarMonth = m.getMonth();
                lunarDay = days + 1;
                break;
            }
        }
        return new Lunar(lunarYear, lunarMonth, lunarDay, solar.getHour(), solar.getMinute(), solar.getSecond(), solar, ly);
    }

    private void computeJieQi(LunarYear y)
    {
        List<Double> jds = y.getJieQiJulianDays();
        for (int i = 0, j = JIE_QI_IN_USE.size(); i < j; i++) {
            this.jieQi.put(JIE_QI_IN_USE.get(i),Solar.fromJulianDay(jds.get(i)));
        }
    }

    private void computeYear()
    {
        int offset = this.year - 4;
        int yearGanIndex = offset % 10;
        int yearZhiIndex = offset % 12;
        if (yearGanIndex < 0) {
            yearGanIndex += 10;
        }
        if (yearZhiIndex < 0) {
            yearZhiIndex += 12;
        }
        int g = yearGanIndex;
        int z = yearZhiIndex;
        int gExact = yearGanIndex;
        int zExact = yearZhiIndex;
        int solarYear = solar.getYear();
        String solarYmd = this.solar.toYmd();
        String solarYmdHms = this.solar.toYmdHms();
        Solar liChun = this.jieQi.get("立春");
        if (liChun.getYear() != solarYear) {
            liChun = jieQi.get("LI_CHUN");
        }
        String liChunYmd = liChun.toYmd();
        String liChunYmdHms = liChun.toYmdHms();
        if (this.year == solarYear) {
            if(solarYmd.compareTo(liChunYmd) < 0){
                g--;
                z--;
            }
            if (solarYmdHms.compareTo(liChunYmdHms) < 0) {
                gExact--;
                zExact--;
            }
        } else if (this.year < solarYear) {
            if (solarYmd.compareTo(liChunYmd) >= 0) {
                g++;
                z++;
            }
            if (solarYmdHms.compareTo(liChunYmdHms) >= 0) {
                gExact++;
                zExact++;
            }
        }
        this.yearGanIndex = yearGanIndex;
        this.yearZhiIndex = yearZhiIndex;
        this.yearGanIndexByLiChun = (g < 0 ? g + 10 : g) % 10;
        this.yearZhiIndexByLiChun = (z < 0 ? z + 12 : z) % 12;
        this.yearGanIndexExact = (gExact < 0 ? gExact + 10 : gExact) % 10;
        this.yearZhiIndexExact = (zExact < 0 ? zExact + 12 : zExact) % 12;
    }

    private void computeMonth()
    {
        Solar start = null;
        String ymd = solar.toYmd();
        String time = solar.toYmdHms();
        int size = JIE_QI_IN_USE.size();
        int index = -3;
        Solar end;
        for (int i = 0; i < size; i += 2) {
            end = jieQi.get(JIE_QI_IN_USE.get(i));
            String symd = (null == start) ? ymd : start.toYmd();
            if (ymd.compareTo(symd) >= 0 && ymd.compareTo(end.toYmd()) < 0) {
                break;
            }
            start = end;
            index++;
        }
        int offset = (((yearGanIndexByLiChun + (index < 0 ? 1 : 0)) % 5 + 1) * 2) % 10;
        monthGanIndex = ((index < 0 ? index + 10 : index) + offset) % 10;
        monthZhiIndex = ((index < 0 ? index + 12 : index) + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12;
        start = null;
        index = -3;
        for (int i = 0; i < size; i += 2) {
            end = jieQi.get(JIE_QI_IN_USE.get(i));
            String stime = null == start ? time : start.toYmdHms();
            if (time.compareTo(stime) >= 0 && time.compareTo(end.toYmdHms()) < 0) {
                break;
            }
            start = end;
            index++;
        }
        offset = (((yearGanIndexExact + (index < 0 ? 1 : 0)) % 5 + 1) * 2) % 10;
        monthGanIndexExact = ((index < 0 ? index + 10 : index) + offset) % 10;
        monthZhiIndexExact = ((index < 0 ? index + 12 : index) + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12;
    }

    private void computeDay()
    {
        Solar noon = Solar.fromYmdHms(solar.getYear(), solar.getMonth(), solar.getDay(), 12, 0, 0);
        int offset = (int) (noon.getJulianDay() - 11);
        int dayGanIndex = offset % 10;
        int dayZhiIndex = offset % 12;
        this.dayGanIndex = dayGanIndex;
        this.dayZhiIndex = dayZhiIndex;
        int dayGanExact = dayGanIndex;
        int dayZhiExact = dayZhiIndex;
        dayGanIndexExact2 = dayGanExact;
        dayZhiIndexExact2 = dayZhiExact;
        String hm = (hour < 10 ? "0" : "") + hour + ":" + (minute < 10 ? "0" : "") + minute;
        if (hm.compareTo("23:00") >= 0 && hm.compareTo("23:59") <= 0) {
            dayGanExact++;
            if (dayGanExact >= 10) {
                dayGanExact -= 10;
            }
            dayZhiExact++;
            if (dayZhiExact >= 12) {
                dayZhiExact -= 12;
            }
        }
        dayGanIndexExact = dayGanExact;
        dayZhiIndexExact = dayZhiExact;
    }

    private void computeTime()
    {
        timeZhiIndex = LunarUtil.getTimeZhiIndex((hour < 10 ? "0" : "") + hour + ":" + (minute < 10 ? "0" : "") + minute);
        timeGanIndex = (dayGanIndexExact % 5 * 2 + timeZhiIndex) % 10;
    }

    private void computeWeek()
    {
        weekIndex = solar.getWeek();
    }

    private void compute(LunarYear y)
    {
        computeJieQi(y);
        computeYear();
        computeMonth();
        computeDay();
        computeTime();
        computeWeek();
    }

    public int getYear()
    {
        return year;
    }

    public int getMonth()
    {
        return month;
    }

    public int getDay()
    {
        return day;
    }

    public int getHour()
    {
        return hour;
    }

    public int getMinute()
    {
        return minute;
    }

    public int getSecond()
    {
        return second;
    }

    public Solar getSolar()
    {
        return solar;
    }

    public String getYearGan()
    {
        return LunarUtil.GAN.get(yearGanIndex + 1);
    }

    public String getYearGanByLiChun()
    {
        return LunarUtil.GAN.get(yearGanIndexByLiChun + 1);
    }

    public String getYearGanExact()
    {
        return LunarUtil.GAN.get(yearGanIndexExact + 1);
    }

    public String getYearZhi()
    {
        return LunarUtil.ZHI.get(yearZhiIndex + 1);
    }

    public String getYearZhiByLiChun()
    {
        return LunarUtil.ZHI.get(yearZhiIndexByLiChun + 1);
    }

    public String getYearZhiExact()
    {
        return LunarUtil.ZHI.get(yearZhiIndexExact + 1);
    }

    public String getYearInGanZhi()
    {
        return getYearGan() + getYearZhi();
    }

    public String getYearInGanZhiByLiChun()
    {
        return getYearGanByLiChun() + getYearZhiByLiChun();
    }

    public String getYearInGanZhiExact()
    {
        return getYearGanExact() + getYearZhiExact();
    }

    public String getMonthInGanZhi()
    {
        return getMonthGan() + getMonthZhi();
    }

    public String getMonthInGanZhiExact()
    {
        return getMonthGanExact() + getMonthZhiExact();
    }

    public String getMonthGan()
    {
        return LunarUtil.GAN.get(monthGanIndex + 1);
    }

    public String getMonthGanExact()
    {
        return LunarUtil.GAN.get(monthGanIndexExact + 1);
    }

    public String getMonthZhi()
    {
        return LunarUtil.ZHI.get(monthZhiIndex + 1);
    }

    public String getMonthZhiExact()
    {
        return LunarUtil.ZHI.get(monthZhiIndexExact + 1);
    }

    public String getDayInGanZhi()
    {
        return getDayGan() + getDayZhi();
    }

    public String getDayInGanZhiExact()
    {
        return getDayGanExact() + getDayZhiExact();
    }

    public String getDayInGanZhiExact2()
    {
        return getDayGanExact2() + getDayZhiExact2();
    }

    public String getDayGan()
    {
        return LunarUtil.GAN.get(dayGanIndex + 1);
    }

    public String getDayGanExact()
    {
        return LunarUtil.GAN.get(dayGanIndexExact + 1);
    }

    public String getDayGanExact2()
    {
        return LunarUtil.GAN.get(dayGanIndexExact2 + 1);
    }

    public String getDayZhi()
    {
        return LunarUtil.ZHI.get(dayZhiIndex + 1);
    }

    public String getDayZhiExact()
    {
        return LunarUtil.ZHI.get(dayZhiIndexExact + 1);
    }

    public String getDayZhiExact2()
    {
        return LunarUtil.ZHI.get(dayZhiIndexExact2 + 1);
    }

    public String getYearShengXiao()
    {
        return LunarUtil.SHENG_XIAO.get(yearZhiIndex + 1);
    }

    public String getYearShengXiaoByLiChun()
    {
        return LunarUtil.SHENG_XIAO.get(yearZhiIndexByLiChun + 1);
    }

    public String getYearShengXiaoExact()
    {
        return LunarUtil.SHENG_XIAO.get(yearZhiIndexExact + 1);
    }

    public String getMonthShengXiao()
    {
        return LunarUtil.SHENG_XIAO.get(monthZhiIndex + 1);
    }

    public String getDayShengXiao()
    {
        return LunarUtil.SHENG_XIAO.get(dayZhiIndex + 1);
    }

    public String getTimeShengXiao()
    {
        return LunarUtil.SHENG_XIAO.get(timeZhiIndex + 1);
    }

    public String getYearInChinese()
    {
        String y = year + "";
        StringBuilder s = new StringBuilder();
        for (int i = 0, j = y.length(); i < j; i++) {
            String substring = y.substring(i, i + 1);
            int index =  Character.codePointAt(substring,0);
            s.append(LunarUtil.NUMBER.get(index - 48));
        }
        return s.toString();
    }

    public String getMonthInChinese()
    {
        return (month < 0 ? "闰" : "") + LunarUtil.MONTH.get(Math.abs(month));
    }

    public String getDayInChinese()
    {
        return LunarUtil.DAY.get(day);
    }

    public String getTimeZhi()
    {
        return LunarUtil.ZHI.get(timeZhiIndex + 1);
    }

    public String getTimeGan()
    {
        return LunarUtil.GAN.get(timeGanIndex + 1);
    }

    public String getTimeInGanZhi()
    {
        return getTimeGan() + getTimeZhi();
    }

    public String getSeason()
    {
        return LunarUtil.SEASON.get(Math.abs(month));
    }

    private String convertJieQi(String name)
    {
        String jq = name;
        if ("DONG_ZHI".compareTo(jq) == 0) {
            jq = "冬至";
        } else if ("DA_HAN".compareTo( jq) == 0) {
            jq = "大寒";
        } else if ("XIAO_HAN".compareTo( jq) == 0) {
            jq = "小寒";
        } else if ("LI_CHUN".compareTo( jq) == 0) {
            jq = "立春";
        } else if ("DA_XUE".compareTo( jq) == 0) {
            jq = "大雪";
        } else if ("YU_SHUI".compareTo(jq) == 0) {
            jq = "雨水";
        } else if ("JING_ZHE".compareTo(jq) == 0) {
            jq = "惊蛰";
        }
        return jq;
    }

    public String getJie()
    {
        for (int i = 0, j = JIE_QI_IN_USE.size(); i < j; i += 2) {
            String key = JIE_QI_IN_USE.get(i);
            Solar d = jieQi.get(key);
            if (d.getYear() == solar.getYear() && d.getMonth() == solar.getMonth() && d.getDay() == solar.getDay()) {
                return convertJieQi(key);
            }
        }
        return "";
    }

    public String getQi()
    {
        for (int i = 1, j = JIE_QI_IN_USE.size(); i < j; i += 2) {
            String key = JIE_QI_IN_USE.get(i);
            Solar d = jieQi.get(key);
            if (d.getYear() == solar.getYear() && d.getMonth() == solar.getMonth() && d.getDay() == solar.getDay()) {
                return convertJieQi(key);
            }
        }
        return "";
    }

    public int getWeek()
    {
        return weekIndex;
    }

    public String getWeekInChinese()
    {
        return SolarUtil.WEEK.get(getWeek());
    }

    public String getXiu()
    {
        return LunarUtil.XIU.get(getDayZhi() + getWeek());
    }

    public String getXiuLuck()
    {
        return LunarUtil.XIU_LUCK.get(getXiu());
    }

    public String getXiuSong()
    {
        return LunarUtil.XIU_SONG.get(getXiu());
    }

    public String getZheng()
    {
        return LunarUtil.ZHENG.get(getXiu());
    }

    public String getAnimal()
    {
        return LunarUtil.ANIMAL.get(getXiu());
    }

    public String getGong()
    {
        return LunarUtil.GONG.get(getXiu());
    }

    public String getShou()
    {
        return LunarUtil.SHOU.get(getGong());
    }

    public List<String> getFestivals()
    {
        List<String> l = new ArrayList<>();
        String key = month + "-" + day;
        if ( !LunarUtil.FESTIVAL.get(key).isEmpty()) {
            l.add(LunarUtil.FESTIVAL.get(key));
        }
        if (Math.abs(month) == 12 && day >= 29 && year != next(1).getYear()) {
            l.add("除夕");
        }
        return l;
    }

    public List<String> getOtherFestivals()
    {
        List<String> l = new ArrayList<>();
        String key = month + "-" + day;
        if (LunarUtil.OTHER_FESTIVAL.get(key).isEmpty()) {
            l.addAll(LunarUtil.OTHER_FESTIVAL.get(key));
        }
        Solar jq = jieQi.get("清明");
        String solarYmd = solar.toYmd();
        if (solarYmd.compareTo(jq.next(-1).toYmd()) == 0) {
            l.add("寒食节");
        }
        jq = jieQi.get("立春");
        int offset = 4 - jq.getLunar().getDayGanIndex();
        if (offset < 0) {
            offset += 10;
        }
        if (solarYmd.compareTo(jq.next(offset + 40).toYmd()) == 0) {
            l.add("春社");
        }
        jq = jieQi.get("立秋");
        offset = 4 - jq.getLunar().getDayGanIndex();
        if (offset < 0) {
            offset += 10;
        }
        if (solarYmd.compareTo(jq.next(offset + 40).toYmd()) == 0) {
            l.add("秋社");
        }
        return l;
    }

    public String getPengZuGan()
    {
        return LunarUtil.PENG_ZU_GAN.get(dayGanIndex + 1);
    }

    public String getPengZuZhi()
    {
        return LunarUtil.PENG_ZU_ZHI.get(dayZhiIndex + 1);
    }

    public String getPositionXi()
    {
        return getDayPositionXi();
    }

    public String getPositionXiDesc()
    {
        return getDayPositionXiDesc();
    }

    public String getDayPositionXi()
    {
        return LunarUtil.POSITION_XI.get(dayGanIndex + 1);
    }

    public String getDayPositionXiDesc()
    {
        return LunarUtil.POSITION_DESC.get(getDayPositionXi());
    }

    public String getTimePositionXi()
    {
        return LunarUtil.POSITION_XI.get(timeGanIndex + 1);
    }

    public String getTimePositionXiDesc()
    {
        return LunarUtil.POSITION_DESC.get(getTimePositionXi());
    }

    public String getPositionYangGui()
    {
        return getDayPositionYangGui();
    }

    public String getPositionYangGuiDesc()
    {
        return getDayPositionYangGuiDesc();
    }

    public String getDayPositionYangGui()
    {
        return LunarUtil.POSITION_YANG_GUI.get(dayGanIndex + 1);
    }

    public String getDayPositionYangGuiDesc()
    {
        return LunarUtil.POSITION_DESC.get(getDayPositionYangGui());
    }

    public String getTimePositionYangGui()
    {
        return LunarUtil.POSITION_YANG_GUI.get(timeGanIndex + 1);
    }

    public String getTimePositionYangGuiDesc()
    {
        return LunarUtil.POSITION_DESC.get(getTimePositionYangGui());
    }

    public String getPositionYinGui()
    {
        return getDayPositionYinGui();
    }

    public String getPositionYinGuiDesc()
    {
        return getDayPositionYinGuiDesc();
    }

    public String getDayPositionYinGui()
    {
        return LunarUtil.POSITION_YIN_GUI.get(dayGanIndex + 1);
    }

    public String getDayPositionYinGuiDesc()
    {
        return LunarUtil.POSITION_DESC.get(getDayPositionYinGui());
    }

    public String getTimePositionYinGui()
    {
        return LunarUtil.POSITION_YIN_GUI.get(timeGanIndex + 1);
    }

    public String getTimePositionYinGuiDesc()
    {
        return LunarUtil.POSITION_DESC.get(getTimePositionYinGui());
    }

    public String getPositionFu()
    {
        return getDayPositionFu();
    }

    public String getPositionFuDesc()
    {
        return getDayPositionFuDesc();
    }

    public String getDayPositionFu()
    {
        return getDayPositionFuBySect(2);
    }

    public String getDayPositionFuBySect(int sect)
    {
        List<String> fu = 1 == sect ? LunarUtil.POSITION_FU : LunarUtil.POSITION_FU_2;
        return fu.get(dayGanIndex + 1);
    }

    public String getDayPositionFuDesc()
    {
        return getDayPositionFuDescBySect(2);
    }

    public String getDayPositionFuDescBySect(int sect)
    {
        return LunarUtil.POSITION_DESC.get(getDayPositionFuBySect(sect));
    }

    public String getTimePositionFu()
    {
        return getTimePositionFuBySect(2);
    }

    public String getTimePositionFuBySect(int sect)
    {
        List<String> fu = 1 == sect ? LunarUtil.POSITION_FU : LunarUtil.POSITION_FU_2;
        return fu.get(timeGanIndex + 1);
    }

    public String getTimePositionFuDesc()
    {
        return getTimePositionFuDescBySect(2);
    }

    public String getTimePositionFuDescBySect(int sect)
    {
        return LunarUtil.POSITION_DESC.get(getTimePositionFuBySect(sect));
    }

    public String getPositionCai()
    {
        return getDayPositionCai();
    }

    public String getPositionCaiDesc()
    {
        return getDayPositionCaiDesc();
    }

    public String getDayPositionCai()
    {
        return LunarUtil.POSITION_CAI.get(dayGanIndex + 1);
    }

    public String getDayPositionCaiDesc()
    {
        return LunarUtil.POSITION_DESC.get(getDayPositionCai());
    }

    public String getTimePositionCai()
    {
        return LunarUtil.POSITION_CAI.get(timeGanIndex + 1);
    }

    public String getTimePositionCaiDesc()
    {
        return LunarUtil.POSITION_DESC.get(getTimePositionCai());
    }

    public String getYearPositionTaiSui()
    {
        return getYearPositionTaiSuiBySect(2);
    }

    public String getYearPositionTaiSuiBySect(int sect)
    {
        switch (sect) {
            case 1:
                yearZhiIndex = yearZhiIndex;
                break;
            case 3:
                yearZhiIndex = yearZhiIndexExact;
                break;
            default:
                yearZhiIndex = yearZhiIndexByLiChun;
        }
        return LunarUtil.POSITION_TAI_SUI_YEAR.get(yearZhiIndex);
    }

    public String getYearPositionTaiSuiDesc()
    {
        return getYearPositionTaiSuiDescBySect(2);
    }

    public String getYearPositionTaiSuiDescBySect(int sect)
    {
        return LunarUtil.POSITION_DESC.get(getYearPositionTaiSuiBySect(sect));
    }

    protected String _getMonthPositionTaiSui(int monthZhiIndex, int monthGanIndex)
    {
        int m = monthZhiIndex - LunarUtil.BASE_MONTH_ZHI_INDEX;
        if (m < 0) {
            m += 12;
        }
        String p;
        switch (m) {
            case 0:
            case 4:
            case 8:
                p = "艮";
                break;
            case 2:
            case 6:
            case 10:
                p = "坤";
                break;
            case 3:
            case 7:
            case 11:
                p = "巽";
                break;
            default:
                p = LunarUtil.POSITION_GAN.get(monthGanIndex);
        }
        return p;
    }

    public String getMonthPositionTaiSuiBySect(int sect)
    {
        switch (sect) {
            case 3:
                monthZhiIndex = monthZhiIndexExact;
                monthGanIndex = monthGanIndexExact;
                break;
            default:
                monthZhiIndex = monthZhiIndex;
                monthGanIndex = monthGanIndex;
        }
        return _getMonthPositionTaiSui(monthZhiIndex, monthGanIndex);
    }

    public String getMonthPositionTaiSui()
    {
        return getMonthPositionTaiSuiBySect(2);
    }

    public String getMonthPositionTaiSuiDesc()
    {
        return getMonthPositionTaiSuiDescBySect(2);
    }

    public String getMonthPositionTaiSuiDescBySect(int sect)
    {
        return LunarUtil.POSITION_DESC.get(getMonthPositionTaiSuiBySect(sect));
    }

    protected String _getDayPositionTaiSui(String dayInGanZhi, int yearZhiIndex)
    {
        String p;
        if ("甲子,乙丑,丙寅,丁卯,戊辰,已巳".contains(dayInGanZhi)) {
            p = "震";
        } else if ("丙子,丁丑,戊寅,已卯,庚辰,辛巳".contains(dayInGanZhi) ) {
            p = "离";
        } else if ("戊子,已丑,庚寅,辛卯,壬辰,癸巳".contains( dayInGanZhi) ) {
            p = "中";
        } else if ("庚子,辛丑,壬寅,癸卯,甲辰,乙巳".contains( dayInGanZhi) ) {
            p = "兑";
        } else if ("壬子,癸丑,甲寅,乙卯,丙辰,丁巳".contains( dayInGanZhi)) {
            p = "坎";
        } else {
            p = LunarUtil.POSITION_TAI_SUI_YEAR.get(yearZhiIndex);
        }
        return p;
    }

    public String getDayPositionTaiSuiBySect(int sect)
    {
        String dayInGanZhi;
        switch (sect) {
            case 1:
                dayInGanZhi = getDayInGanZhi();
                yearZhiIndex = yearZhiIndex;
                break;
            case 3:
                dayInGanZhi = getDayInGanZhi();
                yearZhiIndex = yearZhiIndexExact;
                break;
            default:
                dayInGanZhi = getDayInGanZhiExact2();
                yearZhiIndex = yearZhiIndexByLiChun;
        }
        return _getDayPositionTaiSui(dayInGanZhi, yearZhiIndex);
    }

    public String getDayPositionTaiSui()
    {
        return getDayPositionTaiSuiBySect(2);
    }

    public String getDayPositionTaiSuiDesc()
    {
        return getDayPositionTaiSuiDescBySect(2);
    }

    public String getDayPositionTaiSuiDescBySect(int sect)
    {
        return LunarUtil.POSITION_DESC.get(getDayPositionTaiSuiBySect(sect));
    }

    public String getChong()
    {
        return getDayChong();
    }

    public String getDayChong()
    {
        return LunarUtil.CHONG.get(dayZhiIndex);
    }

    public String getTimeChong()
    {
        return LunarUtil.CHONG.get(timeZhiIndex);
    }

    public String getChongGan()
    {
        return getDayChongGan();
    }

    public String getDayChongGan()
    {
        return LunarUtil.CHONG_GAN.get(dayGanIndex);
    }

    public String getTimeChongGan()
    {
        return LunarUtil.CHONG_GAN.get(timeGanIndex);
    }

    public String getChongGanTie()
    {
        return getDayChongGanTie();
    }

    public String getDayChongGanTie()
    {
        return LunarUtil.CHONG_GAN_TIE.get(dayGanIndex);
    }

    public String getTimeChongGanTie()
    {
        return LunarUtil.CHONG_GAN_TIE.get(timeGanIndex);
    }

    public String getChongShengXiao()
    {
        return getDayChongShengXiao();
    }

    public String getDayChongShengXiao()
    {
        String chong = getDayChong();
        for (int i = 0, j = LunarUtil.ZHI.size(); i < j; i++) {
            if (LunarUtil.ZHI.get(i).compareTo(chong) == 0) {
                return LunarUtil.SHENG_XIAO.get(i);
            }
        }
        return "";
    }

    public String getTimeChongShengXiao()
    {
        String chong = getTimeChong();
        for (int i = 0, j = LunarUtil.ZHI.size(); i < j; i++) {
            if (LunarUtil.ZHI.get(i).compareTo(chong) == 0) {
                return LunarUtil.SHENG_XIAO.get(i);
            }
        }
        return "";
    }

    public String getChongDesc()
    {
        return getDayChongDesc();
    }

    public String getDayChongDesc()
    {
        return "(" + getDayChongGan() + getDayChong() + ")" + getDayChongShengXiao();
    }

    public String getTimeChongDesc()
    {
        return "(" + getTimeChongGan() + getTimeChong() + ")" + getTimeChongShengXiao();
    }

    public String getSha()
    {
        return getDaySha();
    }

    public String getDaySha()
    {
        return LunarUtil.SHA.get(getDayZhi());
    }

    public String getTimeSha()
    {
        return LunarUtil.SHA.get(getTimeZhi());
    }

    public String getYearNaYin()
    {
        return LunarUtil.NAYIN.get(getYearInGanZhi());
    }

    public String getMonthNaYin()
    {
        return LunarUtil.NAYIN.get(getMonthInGanZhi());
    }

    public String getDayNaYin()
    {
        return LunarUtil.NAYIN.get(getDayInGanZhi());
    }

    public String getTimeNaYin()
    {
        return LunarUtil.NAYIN.get(getTimeInGanZhi());
    }

    public List<String> getBaZi()
    {
        EightChar baZi = getEightChar();
        List<String> l = new ArrayList<>();
        l.add(baZi.getYear());
        l.add(baZi.getMonth());
        l.add(baZi.getDay());
        l.add(baZi.getTime());
        return l;
    }

    public List<String> getBaZiWuXing()
    {
        EightChar baZi = getEightChar();
        List<String> l = new ArrayList<>();
        l.add(baZi.getYearWuXing());
        l.add(baZi.getMonthWuXing());
        l.add(baZi.getDayWuXing());
        l.add(baZi.getTimeWuXing());
        return l;
    }

    public List<String> getBaZiNaYin()
    {
        EightChar baZi = getEightChar();
        List<String> l = new ArrayList<>();
        l.add(baZi.getYearNaYin());
        l.add(baZi.getMonthNaYin());
        l.add(baZi.getDayNaYin());
        l.add(baZi.getTimeNaYin());
        return l;
    }

    public List<String> getBaZiShiShenGan()
    {
        EightChar baZi = getEightChar();
        List<String> l = new ArrayList<>();
        l.add(baZi.getYearShiShenGan());
        l.add(baZi.getMonthShiShenGan());
        l.add(baZi.getDayShiShenGan());
        l.add(baZi.getTimeShiShenGan());
        return l;
    }

    public List<String> getBaZiShiShenZhi()
    {
        EightChar baZi = getEightChar();
        List<String> l = new ArrayList<>();
        List<String> yearShiShenZhi = baZi.getYearShiShenZhi();
        List<String> monthShiShenZhi = baZi.getMonthShiShenZhi();
        List<String> dayShiShenZhi = baZi.getDayShiShenZhi();
        List<String> timeShiShenZhi = baZi.getTimeShiShenZhi();
        l.add(yearShiShenZhi.get(0));
        l.add(monthShiShenZhi.get(0));
        l.add(dayShiShenZhi.get(0));
        l.add(timeShiShenZhi.get(0));
        return l;
    }

    public List<String> getBaZiShiShenYearZhi()
    {
        return getEightChar().getYearShiShenZhi();
    }

    public List<String> getBaZiShiShenMonthZhi()
    {
        return getEightChar().getMonthShiShenZhi();
    }

    public List<String> getBaZiShiShenDayZhi()
    {
        return getEightChar().getDayShiShenZhi();
    }

    public List<String> getBaZiShiShenTimeZhi()
    {
        return getEightChar().getTimeShiShenZhi();
    }

    public String getZhiXing()
    {
        int offset = dayZhiIndex - monthZhiIndex;
        if (offset < 0) {
            offset += 12;
        }
        return LunarUtil.ZHI_XING.get(offset + 1);
    }

    public String getDayTianShen()
    {
        return LunarUtil.TIAN_SHEN.get((dayZhiIndex + LunarUtil.ZHI_TIAN_SHEN_OFFSET.get(getMonthZhi())) % 12 + 1);
    }

    public String getTimeTianShen()
    {
        return LunarUtil.TIAN_SHEN.get((timeZhiIndex + LunarUtil.ZHI_TIAN_SHEN_OFFSET.get(getDayZhiExact())) % 12 + 1);
    }

    public String getDayTianShenType()
    {
        return LunarUtil.TIAN_SHEN_TYPE.get(getDayTianShen());
    }

    public String getTimeTianShenType()
    {
        return LunarUtil.TIAN_SHEN_TYPE.get(getTimeTianShen());
    }

    public String getDayTianShenLuck()
    {
        return LunarUtil.TIAN_SHEN_TYPE_LUCK.get(getDayTianShenType());
    }

    public String getTimeTianShenLuck()
    {
        return LunarUtil.TIAN_SHEN_TYPE_LUCK.get(getTimeTianShenType());
    }

    public String getDayPositionTai()
    {
        return LunarUtil.POSITION_TAI_DAY.get(LunarUtil.getJiaZiIndex(getDayInGanZhi()));
    }

    public String getMonthPositionTai()
    {
        if (month < 0) {
            return "";
        }
        return LunarUtil.POSITION_TAI_MONTH.get(month - 1);
    }

    public ArrayList<String> getDayYi()
    {
        return LunarUtil.getDayYi(getMonthInGanZhiExact(), getDayInGanZhi());
    }

    public ArrayList<String> getTimeYi()
    {
        return LunarUtil.getTimeYi(getDayInGanZhiExact(), getTimeInGanZhi());
    }

    public ArrayList<String> getDayJi()
    {
        return LunarUtil.getDayJi(getMonthInGanZhiExact(), getDayInGanZhi());
    }

    public ArrayList<String> getTimeJi()
    {
        return LunarUtil.getTimeJi(getDayInGanZhiExact(), getTimeInGanZhi());
    }

    public ArrayList<String> getDayJiShen()
    {
        return LunarUtil.getDayJiShen(getMonth(), getDayInGanZhi());
    }

    public ArrayList<String> getDayXiongSha()
    {
        return LunarUtil.getDayXiongSha(String.valueOf(getMonth()), getDayInGanZhi());
    }

    public String getYueXiang()
    {
        return LunarUtil.YUE_XIANG.get(getDay());
    }

    protected NineStar _getYearNineStar(String yearInGanZhi)
    {
        int indexExact = LunarUtil.getJiaZiIndex(yearInGanZhi) + 1;
        int index = LunarUtil.getJiaZiIndex(getYearInGanZhi()) + 1;
        int yearOffset = indexExact - index;
        if (yearOffset > 1) {
            yearOffset -= 60;
        } else if (yearOffset < -1) {
            yearOffset += 60;
        }
        int yuan = ((year + yearOffset + 2696) / 60) % 3;
        int offset = (62 + yuan * 3 - indexExact) % 9;
        if (0 == offset) {
            offset = 9;
        }
        return NineStar.fromIndex(offset - 1);
    }

    public NineStar getYearNineStarBySect(int sect)
    {
        String yearInGanZhi;
        switch (sect) {
            case 1:
                yearInGanZhi = getYearInGanZhi();
                break;
            case 3:
                yearInGanZhi = getYearInGanZhiExact();
                break;
            default:
                yearInGanZhi = getYearInGanZhiByLiChun();
        }
        return _getYearNineStar(yearInGanZhi);
    }

    public NineStar getYearNineStar()
    {
        return getYearNineStarBySect(2);
    }

    public NineStar _getMonthNineStar(int yearZhiIndex, int monthZhiIndex)
    {
        int index = yearZhiIndex % 3;
        int n = 27 - (index * 3);
        if (monthZhiIndex < LunarUtil.BASE_MONTH_ZHI_INDEX) {
            n -= 3;
        }
        int offset = (n - monthZhiIndex) % 9;
        return NineStar.fromIndex(offset);
    }

    public NineStar getMonthNineStarBySect(int sect)
    {
        int yearZhiIndex,monthZhiIndex;
        switch (sect) {
            case 1:
                yearZhiIndex = this.yearZhiIndex;
                monthZhiIndex = this.monthZhiIndex;
                break;
            case 3:
                yearZhiIndex = this.yearZhiIndexExact;
                monthZhiIndex = this.monthZhiIndexExact;
                break;
            default:
                 yearZhiIndex = this.yearZhiIndexByLiChun;
                 monthZhiIndex = this.monthZhiIndex;
        }
        return _getMonthNineStar(yearZhiIndex, monthZhiIndex);
    }

    public NineStar getMonthNineStar()
    {
        return getMonthNineStarBySect(2);
    }

    public NineStar getDayNineStar()
    {
        String solarYmd = solar.toYmd();
        Solar dongZhi = jieQi.get("冬至");
        Solar dongZhi2 = jieQi.get("DONG_ZHI");
        Solar xiaZhi = jieQi.get("夏至");
        int dongZhiIndex = LunarUtil.getJiaZiIndex(dongZhi.getLunar().getDayInGanZhi());
        int dongZhiIndex2 = LunarUtil.getJiaZiIndex(dongZhi2.getLunar().getDayInGanZhi());
        int xiaZhiIndex = LunarUtil.getJiaZiIndex(xiaZhi.getLunar().getDayInGanZhi());
        Solar solarShunBai,solarShunBai2,solarNiZi;
        if (dongZhiIndex > 29) {
            solarShunBai = dongZhi.next(60 - dongZhiIndex);
        } else {
            solarShunBai = dongZhi.next(-dongZhiIndex);
        }
        String solarShunBaiYmd = solarShunBai.toYmd();
        if (dongZhiIndex2 > 29) {
            solarShunBai2 = dongZhi2.next(60 - dongZhiIndex2);
        } else {
            solarShunBai2 = dongZhi2.next(-dongZhiIndex2);
        }
        String solarShunBaiYmd2 = solarShunBai2.toYmd();
        if (xiaZhiIndex > 29) {
            solarNiZi = xiaZhi.next(60 - xiaZhiIndex);
        } else {
            solarNiZi = xiaZhi.next(-xiaZhiIndex);
        }
        String solarNiZiYmd = solarNiZi.toYmd();
        int offset = 0;
        if (solarYmd.compareTo(solarShunBaiYmd) >= 0 && solarYmd.compareTo(solarNiZiYmd) < 0) {
            offset = solar.subtract(solarShunBai) % 9;
        } else if (solarYmd.compareTo(solarNiZiYmd) >= 0 && solarYmd.compareTo(solarShunBaiYmd2) < 0) {
            offset = 8 - (solar.subtract(solarNiZi) % 9);
        } else if (solarYmd.compareTo(solarShunBaiYmd2) >= 0) {
            offset = solar.subtract(solarShunBai2) % 9;
        } else if (solarYmd.compareTo( solarShunBaiYmd) < 0) {
            offset = (8 + solarShunBai.subtract(solar)) % 9;
        }
        return NineStar.fromIndex(offset);
    }

    public NineStar getTimeNineStar()
    {
        String solarYmd = solar.toYmd();
        boolean asc = false;
        if (solarYmd.compareTo(jieQi.get("冬至").toYmd()) >= 0 && solarYmd.compareTo(jieQi.get("夏至").toYmd()) < 0) {
            asc = true;
        } else if (solarYmd.compareTo(jieQi.get("DONG_ZHI").toYmd()) >= 0) {
            asc = true;
        }
        int start = asc ? 6 : 2;
        String dayZhi = getDayZhi();
        if ("子午卯酉".contains(dayZhi)) {
            start = asc ? 0 : 8;
        } else if ("辰戌丑未".contains( dayZhi)) {
            start = asc ? 3 : 5;
        }
        int index = asc ? start + timeZhiIndex : start + 9 - timeZhiIndex;
        return NineStar.fromIndex(index % 9);
    }

    public LinkedHashMap<String, Solar> getJieQiTable()
    {
        return jieQi;
    }

    protected JieQi getNearJieQi(boolean forward, List<String> conditions, boolean wholeDay)
    {
        String name = null;
        Solar near = null;
        boolean filter = (null != conditions && conditions.size() > 0);
        String today = wholeDay ? solar.toYmd() : solar.toYmdHms();
        for (String key : jieQi.keySet()) {
            Solar solar = jieQi.get(key);
            String jq = convertJieQi(key);
            if (filter) {
                if (!conditions.contains(jq)) {
                    continue;
                }
            }
            String day = wholeDay ? solar.toYmd() : solar.toYmdHms();
            if (forward) {
                if (day.compareTo(today) < 0) {
                    continue;
                }
                if (null == near) {
                    name = jq;
                    near = solar;
                } else {
                    String nearDay = wholeDay ? near.toYmd() : near.toYmdHms();
                    if (day.compareTo(nearDay) < 0) {
                        name = jq;
                        near = solar;
                    }
                }
            } else {
                if (day.compareTo(today) > 0) {
                    continue;
                }
                if (null == near) {
                    name = jq;
                    near = solar;
                } else {
                    String nearDay = wholeDay ? near.toYmd() : near.toYmdHms();
                    if (day.compareTo(nearDay) > 0) {
                        name = jq;
                        near = solar;
                    }
                }
            }
        }
        if (null == near) {
            return null;
        }
        return new JieQi(name, near);
    }

    public JieQi getNextJieByWholeDay(boolean wholeDay)
    {
        List<String> conditions = new ArrayList<>();
        for (int i = 0, j = JIE_QI_IN_USE.size() / 2+1; i < j; i++) {
            conditions.add(JIE_QI_IN_USE.get(i * 2));
        }
        return getNearJieQi(true, conditions, wholeDay);
    }

    public JieQi getNextJie()
    {
        return getNextJieByWholeDay(false);
    }

    public JieQi getPrevJieByWholeDay(boolean wholeDay)
    {
        List<String> conditions = new ArrayList<>();
        for (int i = 0, j = JIE_QI_IN_USE.size() / 2+1; i < j; i++) {
            conditions.add(JIE_QI_IN_USE.get(i * 2));
        }
        return getNearJieQi(false, conditions, wholeDay);
    }

    public JieQi getPrevJie()
    {
        return getPrevJieByWholeDay(false);
    }

    public JieQi getNextQiByWholeDay(boolean wholeDay)
    {
        List<String> conditions = new ArrayList<>();
        for (int i = 0, j = JIE_QI_IN_USE.size() / 2+1; i < j; i++) {
            conditions.add(JIE_QI_IN_USE.get(i * 2 + 1));
        }
        return getNearJieQi(true, conditions, wholeDay);
    }

    public JieQi getNextQi()
    {
        return getNextQiByWholeDay(false);
    }

    public JieQi getPrevQiByWholeDay(boolean wholeDay)
    {
        List<String> conditions = new ArrayList<>();
        for (int i = 0, j = JIE_QI_IN_USE.size() / 2+1; i < j; i++) {
            conditions.add(JIE_QI_IN_USE.get(i * 2 + 1));
        }
        return getNearJieQi(false, conditions, wholeDay);
    }

    public JieQi getPrevQi()
    {
        return getPrevQiByWholeDay(false);
    }

    public JieQi getNextJieQiByWholeDay(boolean wholeDay)
    {
        return getNearJieQi(true, null, wholeDay);
    }

    public JieQi getNextJieQi()
    {
        return getNextJieQiByWholeDay(false);
    }

    public JieQi getPrevJieQiByWholeDay(boolean wholeDay)
    {
        return getNearJieQi(false, null, wholeDay);
    }

    public JieQi getPrevJieQi()
    {
        return getPrevJieQiByWholeDay(false);
    }

    public String getJieQi()
    {
        for (String key : jieQi.keySet()) {
            Solar d = jieQi.get(key);
            if (d.getYear() == solar.getYear() && d.getMonth() == solar.getMonth() && d.getDay() == solar.getDay()) {
                return convertJieQi(key);
            }
        }
        return "";
    }

    public JieQi getCurrentJieQi()
    {
        for (String key : jieQi.keySet()) {
            Solar d = jieQi.get(key);
            if (d.getYear() == solar.getYear() && d.getMonth() == solar.getMonth() && d.getDay() == solar.getDay()) {
                return new JieQi(key, d);
            }
        }
        return null;
    }

    public JieQi getCurrentJie()
    {
        for (int i = 0, j = JIE_QI_IN_USE.size(); i < j; i += 2) {
            String key = JIE_QI_IN_USE.get(i);
            Solar d = jieQi.get(key);
            if (d.getYear() == solar.getYear() && d.getMonth() == solar.getMonth() && d.getDay() == solar.getDay()) {
                return new JieQi(key, d);
            }
        }
        return null;
    }

    public JieQi getCurrentQi()
    {
        for (int i = 1, j = JIE_QI_IN_USE.size(); i < j; i += 2) {
            String key = JIE_QI_IN_USE.get(i);
            Solar d = jieQi.get(key);
            if (d.getYear() == solar.getYear() && d.getMonth() == solar.getMonth() && d.getDay() == solar.getDay()) {
                return new JieQi(key, d);
            }
        }
        return null;
    }

    public int getTimeGanIndex()
    {
        return timeGanIndex;
    }

    public int getTimeZhiIndex()
    {
        return timeZhiIndex;
    }

    public int getDayGanIndex()
    {
        return dayGanIndex;
    }

    public int getDayZhiIndex()
    {
        return dayZhiIndex;
    }

    public int getMonthGanIndex()
    {
        return monthGanIndex;
    }

    public int getMonthZhiIndex()
    {
        return monthZhiIndex;
    }

    public int getYearGanIndex()
    {
        return yearGanIndex;
    }

    public int getYearZhiIndex()
    {
        return yearZhiIndex;
    }

    public int getYearGanIndexByLiChun()
    {
        return yearGanIndexByLiChun;
    }

    public int getYearZhiIndexByLiChun()
    {
        return yearZhiIndexByLiChun;
    }

    public int getDayGanIndexExact()
    {
        return dayGanIndexExact;
    }

    public int getDayGanIndexExact2()
    {
        return dayGanIndexExact2;
    }

    public int getDayZhiIndexExact()
    {
        return dayZhiIndexExact;
    }

    public int getDayZhiIndexExact2()
    {
        return dayZhiIndexExact2;
    }

    public int getMonthGanIndexExact()
    {
        return monthGanIndexExact;
    }

    public int getMonthZhiIndexExact()
    {
        return monthZhiIndexExact;
    }

    public int getYearGanIndexExact()
    {
        return yearGanIndexExact;
    }

    public int getYearZhiIndexExact()
    {
        return yearZhiIndexExact;
    }

    public EightChar getEightChar()
    {
        if (null == eightChar) {
            eightChar = EightChar.fromLunar(this);
        }
        return eightChar;
    }

    public Lunar next(int days)
    {
        return solar.next(days).getLunar();
    }

    public String toFullString()
    {
        StringBuilder s = new StringBuilder();
        s.append(this);
        s.append(" ");
        s.append(getYearInGanZhi());
        s.append("(");
        s.append(getYearShengXiao());
        s.append(")年 ");
        s.append(getMonthInGanZhi());
        s.append("(");
        s.append(getMonthShengXiao());
        s.append(")月 ");
        s.append(getDayInGanZhi());
        s.append("(");
        s.append(getDayShengXiao());
        s.append(")日 ");
        s.append(getTimeZhi());
        s.append("(");
        s.append(getTimeShengXiao());
        s.append(")时 纳音.get(");
        s.append(getYearNaYin());
        s.append(" ");
        s.append(getMonthNaYin());
        s.append(" ");
        s.append(getDayNaYin());
        s.append(" ");
        s.append(getTimeNaYin());
        s.append(") 星期");
        s.append(getWeekInChinese());
        for (String festival : getFestivals()) {
            s.append(" (").append(festival).append(")");
        }
        for (String otherFestival : getOtherFestivals()) {
            s.append(" (").append(otherFestival).append(")");
        }
        String jq = getJieQi();
        if (!jq.isEmpty()) {
            s.append(" (").append(jq).append(")");
        }
        s.append(" ");
        s.append(getGong());
        s.append("方");
        s.append(getShou());
        s.append(" 星宿.get(");
        s.append(getXiu());
        s.append(getZheng());
        s.append(getAnimal());
        s.append(")(");
        s.append(getXiuLuck());
        s.append(") 彭祖百忌.get(");
        s.append(getPengZuGan());
        s.append(" ");
        s.append(getPengZuZhi());
        s.append(") 喜神方位.get(");
        s.append(getDayPositionXi());
        s.append(")(");
        s.append(getDayPositionXiDesc());
        s.append(") 阳贵神方位.get(");
        s.append(getDayPositionYangGui());
        s.append(")(");
        s.append(getDayPositionYangGuiDesc());
        s.append(") 阴贵神方位.get(");
        s.append(getDayPositionYinGui());
        s.append(")(");
        s.append(getDayPositionYinGuiDesc());
        s.append(") 福神方位.get(");
        s.append(getDayPositionFu());
        s.append(")(");
        s.append(getDayPositionFuDesc());
        s.append(") 财神方位.get(");
        s.append(getDayPositionCai());
        s.append(")(");
        s.append(getDayPositionCaiDesc());
        s.append(") 冲.get(");
        s.append(getChongDesc());
        s.append(") 煞.get(");
        s.append(getSha());
        s.append(")");
        return s.toString();
    }

    @Override
    public String toString()
    {
        return getYearInChinese() + "年" + getMonthInChinese() + "月" + getDayInChinese();
    }


    public String getYearXun()
    {
        return LunarUtil.getXun(getYearInGanZhi());
    }

    public String getYearXunByLiChun()
    {
        return LunarUtil.getXun(getYearInGanZhiByLiChun());
    }

    public String getYearXunExact()
    {
        return LunarUtil.getXun(getYearInGanZhiExact());
    }

    public String getYearXunKong()
    {
        return LunarUtil.getXunKong(getYearInGanZhi());
    }

    public String getYearXunKongByLiChun()
    {
        return LunarUtil.getXunKong(getYearInGanZhiByLiChun());
    }

    public String getYearXunKongExact()
    {
        return LunarUtil.getXunKong(getYearInGanZhiExact());
    }

    public String getMonthXun()
    {
        return LunarUtil.getXun(getMonthInGanZhi());
    }

    public String getMonthXunExact()
    {
        return LunarUtil.getXun(getMonthInGanZhiExact());
    }

    public String getMonthXunKong()
    {
        return LunarUtil.getXunKong(getMonthInGanZhi());
    }

    public String getMonthXunKongExact()
    {
        return LunarUtil.getXunKong(getMonthInGanZhiExact());
    }

    public String getDayXun()
    {
        return LunarUtil.getXun(getDayInGanZhi());
    }

    public String getDayXunExact()
    {
        return LunarUtil.getXun(getDayInGanZhiExact());
    }

    public String getDayXunExact2()
    {
        return LunarUtil.getXun(getDayInGanZhiExact2());
    }

    public String getDayXunKong()
    {
        return LunarUtil.getXunKong(getDayInGanZhi());
    }

    public String getDayXunKongExact()
    {
        return LunarUtil.getXunKong(getDayInGanZhiExact());
    }

    public String getDayXunKongExact2()
    {
        return LunarUtil.getXunKong(getDayInGanZhiExact2());
    }

    public String getTimeXun()
    {
        return LunarUtil.getXun(getTimeInGanZhi());
    }

    public String getTimeXunKong()
    {
        return LunarUtil.getXunKong(getTimeInGanZhi());
    }

    public ShuJiu getShuJiu()
    {
        Solar current = Solar.fromYmd(solar.getYear(), solar.getMonth(), solar.getDay());
        Solar start = jieQi.get("DONG_ZHI");
        start = Solar.fromYmd(start.getYear(), start.getMonth(), start.getDay());
        if (current.isBefore(start)) {
            start = jieQi.get("冬至");
            start = Solar.fromYmd(start.getYear(), start.getMonth(), start.getDay());
        }
        Solar end = Solar.fromYmd(start.getYear(), start.getMonth(), start.getDay()).next(81);
        if (current.isBefore(start) || (!current.isBefore(end))) {
            return null;
        }
        int days = current.subtract(start);
        return new ShuJiu(LunarUtil.NUMBER.get((int)(days / 9) + 1) + "九", days % 9 + 1);
    }

    public Fu getFu()
    {
        Solar current = Solar.fromYmd(solar.getYear(), solar.getMonth(), solar.getDay());
        Solar xiaZhi = jieQi.get("夏至");
        Solar liQiu = jieQi.get("立秋");
        Solar start = Solar.fromYmd(xiaZhi.getYear(), xiaZhi.getMonth(), xiaZhi.getDay());
        int add = 6 - xiaZhi.getLunar().getDayGanIndex();
        if (add < 0) {
            add += 10;
        }
        add += 20;
        start = start.next(add);
        if (current.isBefore(start)) {
            return null;
        }
        int days = current.subtract(start);
        if (days < 10) {
            return new Fu("初伏", days + 1);
        }
        start = start.next(10);
        days = current.subtract(start);
        if (days < 10) {
            return new Fu("中伏", days + 1);
        }
        start = start.next(10);
        days = current.subtract(start);
        Solar liQiuSolar = Solar.fromYmd(liQiu.getYear(), liQiu.getMonth(), liQiu.getDay());
        if (!liQiuSolar.isAfter(start)) {
            if (days < 10) {
                return new Fu("末伏", days + 1);
            }
        } else {
            if (days < 10) {
                return new Fu("中伏", days + 11);
            }
            start = start.next(10);
            days = current.subtract(start);
            if (days < 10) {
                return new Fu("末伏", days + 1);
            }
        }
        return null;
    }

    public String getLiuYao()
    {
        return LunarUtil.LIU_YAO.get((Math.abs(month) + day - 2) % 6);
    }

    public String getWuHou()
    {
        JieQi jieQi = getPrevJieQiByWholeDay(true);
        int offset = 0;
        for (int i = 0, j = JIE_QI.size(); i < j; i++) {
            if (jieQi.getName().compareTo( JIE_QI.get(i)) == 0) {
                offset = i;
                break;
            }
        }
        int index = (int)(solar.subtract(jieQi.getSolar()) / 5);
        if (index > 2) {
            index = 2;
        }
        return LunarUtil.WU_HOU.get((offset * 3 + index) % LunarUtil.WU_HOU.size());
    }

    public String getHou()
    {
        JieQi jieQi = getPrevJieQiByWholeDay(true);
        int max = LunarUtil.HOU.size() - 1;
        double offset = Math.floor(solar.subtract(jieQi.getSolar()) / 5);
        if (offset > max) {
            offset = max;
        }
        return jieQi.getName() + " " + LunarUtil.HOU.get((int) offset);
    }

    public String getDayLu()
    {
        String gan = LunarUtil.LU.get(getDayGan());
        String zhi = null;
        if (!LunarUtil.LU.get(getDayZhi()).isEmpty()) {
            zhi = LunarUtil.LU.get(getDayZhi());
        }
        String lu = gan + "命互禄";
        if (null != zhi) {
            lu += " " + zhi + "命进禄";
        }
        return lu;
    }

    public LunarTime getTime()
    {
        return LunarTime.fromYmdHms(year, month, day, hour, minute, second);
    }

    public List<LunarTime> getTimes()
    {
        List<LunarTime> l = new ArrayList<>();
        l.add(LunarTime.fromYmdHms(year, month, day, 0, 0, 0));
        for (int i = 0; i < 12; i++) {
            l.add(LunarTime.fromYmdHms(year, month, day, (i + 1) * 2 - 1, 0, 0));
        }
        return l;
    }

    public Foto getFoto()
    {
        return Foto.fromLunar(this);
    }

    public Tao getTao()
    {
        return Tao.fromLunar(this);
    }

    public static void main(String[] args) {
        System.out.println("lunar");
    }
}
